[a11y] WCAG 4.1.2 — require label on CodeBlock primitive; add aria-readonly for read-only mode#3557
Open
rosanusi wants to merge 2 commits into
Open
[a11y] WCAG 4.1.2 — require label on CodeBlock primitive; add aria-readonly for read-only mode#3557rosanusi wants to merge 2 commits into
rosanusi wants to merge 2 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
… read-only mode
Makes the `label` prop required on the CodeBlock primitive so every
CodeMirror instance gets an accessible name via `aria-label` on the
`.cm-content` element. Adds `aria-readonly="true"` when `editable=false`
so AT correctly conveys non-editability (JAWS forms-mode fix). Adds a
dev-time `onMount` guard that throws if label is empty after mount.
Migrates all ~28 affected files: primitive, 4 domain wrappers
(PayloadCodeBlock, PayloadInput, InputAndResultsPayload,
PayloadInputWithEncoding), and ~22 direct consumers across Workflow
History, Queries, Schedules, Activities, Events, Workers, and Archival.
Also fixes the PayloadInput orphaned <Label for> association (§NEW1):
replaces <Label for={id}> with <span> and forwards label to the inner
CodeBlock so the accessible name is set on the cm-content element rather
than a wrapper div that for= can't reach.
New i18n keys: common.json, events.import-format-{1,2},
standalone-activities.{activity-input,activity-outcome,cluster-config,
namespace-config}, workers.{heartbeat-config,setup-guide-command},
workflows.{query-result,callback-metadata,update-input,update-result}.
A11y-Audit-Ref: 4.1.2-codemirror-no-name
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
80242bc to
9dc61c2
Compare
| <div class="flex flex-col gap-2"> | ||
| <h5>Input</h5> | ||
| <PayloadCodeBlock value={input} /> | ||
| <PayloadCodeBlock |
Contributor
There was a problem hiding this comment.
⚠️ Type 'IPayloads | undefined' is not assignable to type 'object | IPayloads | IPayload'.
| </p> | ||
| {#key activity.attempt} | ||
| <PayloadCodeBlock value={activity.heartbeatDetails} maxHeight={384} /> | ||
| <PayloadCodeBlock |
Contributor
There was a problem hiding this comment.
⚠️ Type 'IPayloads | null | undefined' is not assignable to type 'object | IPayloads | IPayload'.
| <div class="flex flex-col gap-2"> | ||
| {#if searchAttributes} | ||
| <PayloadCodeBlock value={searchAttributes.indexedFields} /> | ||
| <PayloadCodeBlock |
Contributor
There was a problem hiding this comment.
⚠️ Type 'Record<string, IPayload> | undefined' is not assignable to type 'object | IPayloads | IPayload'.
| {translate('events.attribute-group.search-attributes')} | ||
| </h3> | ||
| <PayloadCodeBlock value={workflow.searchAttributes.indexedFields} /> | ||
| <PayloadCodeBlock |
Contributor
There was a problem hiding this comment.
⚠️ Type 'Record<string, string> | undefined' is not assignable to type 'object | IPayloads | IPayload'.
| label={translate('workflows.query-result')} | ||
| copyIconTitle={translate('common.copy-icon-title')} | ||
| copySuccessIconTitle={translate('common.copy-success-icon-title')} | ||
| testId="query-result" |
Contributor
There was a problem hiding this comment.
⚠️ Type 'false | "opacity-50"' is not assignable to type 'string | undefined'.
| </h3> | ||
| {#if workflow?.searchAttributes} | ||
| <PayloadCodeBlock value={workflow.searchAttributes.indexedFields} /> | ||
| <PayloadCodeBlock |
Contributor
There was a problem hiding this comment.
⚠️ Type 'Record<string, string> | undefined' is not assignable to type 'object | IPayloads | IPayload'.
Contributor
|
code-block.stories.svelte: add label to "With Header" and "Test page scrolling" stories which were missing the now-required prop. compute-fields.svelte: add label to the Terraform IAM template CodeBlock added in the serverless worker form refactor (landed in main after the original PR was cut). Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
| label="Code example" | ||
| tabs={['File A', 'File B']} | ||
| bind:activeTab | ||
| content={hidden |
Contributor
There was a problem hiding this comment.
⚠️ Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ 'File A': string; 'File B': string; }'.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
label: stringrequired on theCodeBlockprimitive (src/lib/holocene/code-block.svelte), applied to CodeMirror's.cm-contentviaEditorView.contentAttributes.of({ 'aria-label': label })— every CodeMirror instance now has an accessible namearia-readonly="true"tocontentAttributeswheneditable=falseso AT (especially JAWS forms-mode) correctly conveys non-editability instead of announcing the element as an editable text fieldonMountguard that throws (dev) /console.errors (prod) whenlabelis empty at mount, catching dynamic-spread cases that TypeScript can't reach<Label for={id}>association inPayloadInput(§NEW1): replaces<Label for>with<span>and forwardslabelto the inner<CodeBlock>so the accessible name lands on the labelable.cm-contentelementAffected files
Primitive + wrappers (5 files):
src/lib/holocene/code-block.sveltesrc/lib/components/payload/payload-code-block.sveltesrc/lib/components/payload-input.sveltesrc/lib/components/payload-input-with-encoding.sveltesrc/lib/components/workflow/input-and-results-payload.svelteLocale additions (5 files):
src/lib/i18n/locales/en/common.ts—jsonsrc/lib/i18n/locales/en/events.ts—import-format-1,import-format-2src/lib/i18n/locales/en/standalone-activities.ts—activity-input,activity-outcome,cluster-config,namespace-configsrc/lib/i18n/locales/en/workers.ts—heartbeat-config,setup-guide-commandsrc/lib/i18n/locales/en/workflows.ts—query-result,callback-metadata,update-input,update-resultDirect consumers (~23 files): event-card, workflow-error-stack-trace, schedules-calendar-view, schedule-frequency-panel, activity-input-and-outcome, standalone-activities-disabled, serverless-worker-setup-guide, worker-heartbeats-disabled, update-confirmation-modal, pending-activities, pending-activity-card, pending-nexus-operation-card, workflow-callback, workflow-json-navigator, import-events, standalone-activity-details, standalone-activity-search-attributes, workflow-call-stack, workflow-memo, workflow-metadata, workflow-query, workflow-search-attributes, archival/+page
Test plan
.cm-contentannounces correct label; JAWS does not auto-switch to forms mode on read-only blocksaria-readonlyabsent<CodeBlock content="…" label="" />— confirm it throws; add non-emptylabel— confirm no throwpnpm checkpasses (no new type errors beyond pre-existing$$_$$slot interop errors on main)PayloadInputstandalone (e.g. update-confirmation-modal): visible<span>label text renders correctly; CodeBlock hasaria-labelA11y-Audit-Ref: 4.1.2-codemirror-no-name
🤖 Generated with Claude Code